﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Entity;
using System.Linq;
using EntityFramework6.Services;
using EntityFramework6.Services.Data;

namespace EntityFramework6._1Examples
{
    class Program
    {
        static void Main(string[] args)
        {

            using (var context = new BookContext())
            {
                ReadAllBooks(context);

                EagerLoadBookAuthors(context);

                LazyLoadBookAuthors(context);

                LoadUsingSqlQuery(context);

                LoadDataUsingSqlFromMoreThanOneTable(context);

            }

            // HandleMultiEntityTransaction();
            
            Console.ReadLine();
        }

        private static void HandleMultiEntityTransaction()
        {
            using (var context = new BookContext())
            {
                using (var transaction = context.Database.BeginTransaction()) // Begin transaction
                {
                    try
                    {
                        // add author
                        var author = new Author() {Name = "Maria Robinlius"};
                        context.Authors.Add(author);
                        context.SaveChanges();                 // Save Entity 1

                        // add publisher
                        var publisher = new Publisher() {PublisherName = "ABC"};
                        context.Publishers.Add(publisher);
                        context.SaveChanges();                  // Save Entity 2
                        var publisherId = publisher.Id;
                        
                        // add book
                        var book = new Book()
                        {
                            Category = Category.Design,
                            Name = "New book",
                            Price = 155,
                            PublishedDate = new DateTime(2014, 12, 12),
                            Authors = new List<Author>(){author},
                            PublisherId = publisherId
                        };

                        context.Books.Add(book);
                        context.SaveChanges();                      // Save Entity 3

                        transaction.Commit();                       // Commit transaction
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        Console.WriteLine(ex.Message);
                    }
                }
            }
        }

        private static void LoadDataUsingSqlFromMoreThanOneTable(BookContext context)
        {
            // loads data to custom Dtos without tracking
            var authorsBooks =
                context.Database.SqlQuery<AuthorsBooks>("select distinct count(b.id) as TotalBooks, a.Name as Author  from Authors a  inner join BookAuthors ba on a.Id = ba.Author_Id inner join Books b on b.ID = ba.Book_ID group by a.Name");
            foreach (var authorBook in authorsBooks)
            {
                DumpAllProperties(authorBook);
            }
        }

        private static void LoadUsingSqlQuery(BookContext context)
        {
            // Loading using SQL for a entity
            var authors = context.Authors.SqlQuery("select * from Authors");
            foreach (var author in authors)
            {
                DumpAllProperties(author);
            }
        }

        private static void LazyLoadBookAuthors(BookContext context)
        {
            var books = from b in context.Books
                        select b;

            foreach (var book in books)
            {
                foreach (var author in book.Authors)
                {
                    DumpAllProperties(author);
                }
            }
        }

        private static void EagerLoadBookAuthors(BookContext context)
        {
            // Eager load the authers!!
            var books = from b in context.Books.Include(a => a.Authors)
                select b;

            foreach (var book in books)
            {
                foreach (var author in book.Authors)
                {
                    DumpAllProperties(author);
                }
            }
        }

        private static void ReadAllBooks(BookContext context)
        {
                var books = from b in context.Books
                    select b;

                foreach (var book in books)
                {
                    DumpAllProperties(book);
                }
        }

        private static void DumpAllProperties(object obj)
        {
            foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(obj))
            {
                //Console.WriteLine("->" + descriptor.PropertyType.FullName);

                if (!descriptor.PropertyType.IsValueType && descriptor.PropertyType.FullName!="System.String")
                {
                    //DumpAllProperties(descriptor);
                    // ignore it
                }
                else
                {
                    string name = descriptor.Name;
                    object value = descriptor.GetValue(obj);
                    Console.WriteLine("{0}={1}", name, value);
                }

            }
        }
    }
}
